package com.hyt.it.ogt.kq.common.gov.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;

import com.hyt.it.ogt.kq.common.gov.xml.driver.NoneEscapeAppDriver;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.AbstractDriver;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.Xpp3Driver;
import com.thoughtworks.xstream.security.AnyTypePermission;

import lombok.extern.slf4j.Slf4j;

/**
 * XML工具类
 *
 * @author huangyh
 * @since 2021/2/4 12:50
 */
@Slf4j
public class XmlUtil {

    private final static String header = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

    /**
     * 字符串添加cdata标签
     *
     * @param string 字符串
     * @return 添加了cdata标签的字符串
     */
    public static String stringToCdata(String string) {
        return "<![CDATA[" + string + "]]>";
    }

    /**
     * xml文本加入top
     *
     * @param xml xml文本
     * @return 加入top的xml文本
     */
    public static String addHeader(String xml) {
        return header + xml;
    }

    /**
     * 对象转换为XML字符串
     *
     * @param object 对象
     * @return XML字符串
     */
    public static String toXml(Object object) {
        XStream xStream = new XStream();
        xStream.processAnnotations(object.getClass());
        return xStream.toXML(object);
    }

    /**
     * 指定XML驱动将对象转换为XML字符串
     *
     * @param object    对象
     * @param xmlDriver XML驱动
     * @return XML字符串
     */
    public static String toXml(Object object, AbstractDriver xmlDriver) {
        XStream xStream = new XStream(xmlDriver);
        xStream.processAnnotations(object.getClass());
        return xStream.toXML(object);
    }

    /**
     * 对象转换为XML字符串（不转义特殊字符）
     * @param obj 对象
     * @return XML字符串
     */
    public static String toXmlWithNoneEscape(Object obj) {
        XStream xStream = new XStream(new NoneEscapeAppDriver());
        xStream.processAnnotations(obj.getClass());
        return xStream.toXML(obj);
    }

    public static String toXmlWithHeader(Object obj) {
        XStream xs = new XStream(new Xpp3Driver(new NoNameCoder()));
        xs.processAnnotations(obj.getClass());
        return header.concat(xs.toXML(obj));
    }

    /**
     * 对象转换为XML字符串并拼接上header（不转义特殊字符）
     * @param obj 对象
     * @return XML字符串
     */
    public static String toXmlWithNoneEscapeAndHeader(Object obj) {
        XStream xStream = new XStream(new NoneEscapeAppDriver());
        xStream.processAnnotations(obj.getClass());
        return header.concat(xStream.toXML(obj));
    }

    /**
     * XML字符串转换为对象
     *
     * @param xml   XML字符串
     * @param clazz 要转换的对象的类型
     * @param <T>   泛型
     * @return 对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T toObject(String xml, Class<T> clazz) {
        XStream xStream = new XStream(new DomDriver());
        xStream.setClassLoader(clazz.getClassLoader());
        xStream.addPermission(AnyTypePermission.ANY);
        xStream.processAnnotations(clazz);
        return (T) xStream.fromXML(xml);
    }

    /**
     * 读取xml文件中的某个节点数据
     *
     * @param xmlContent
     * @param node
     * @return
     */
    public static String readXmlOneNode(String xmlContent, String node) {
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlContent);
            Node n = document.selectSingleNode(node);
            if (n != null) {
                return n.getStringValue();
            }
        } catch (Exception e) {
            log.error("读取xml数据节点出错，e", e);
            return null;
        }
        return null;
    }


    public static String toXmlByNoNameCoder(Object obj) {
        XStream xstream = new XStream(new Xpp3Driver(new NoNameCoder()));
        ////如果没有这句，xml中的根元素会是<包.类名>；或者说：注解根本就没生效，所以的元素名就是类的属性
        xstream.processAnnotations(obj.getClass());
        return xstream.toXML(obj);
    }

    public static boolean toXmlFile(Object obj, String filePath) {
        String xml = toXmlByNoNameCoder(obj);
        File file = new File(filePath);
        if (!file.exists()) {
            try {
                boolean newFile = file.createNewFile();
                log.info("创建新文件：{} {} {}", obj, filePath, newFile);
            } catch (IOException e) {
                log.error("", e);
                return false;
            }
        }
        String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + xml.replaceAll("&quot;", "\"");
        return writeFile(content, file);
    }

    public static boolean writeFile(String content, File file){
        OutputStreamWriter ow = null;
        try {
            ow = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
            ow.write(content);
            ow.flush();
        } catch (Exception e) {
            log.error("写入xml文件异常", e);
            return false;
        } finally {
            if (ow != null) {
                try {
                    ow.close();
                } catch (IOException i) {
                    log.error("关闭OutputStreamWriter异常", i);
                }
            }
        }
        return true;
    }

    public static boolean toXmlFile(Object obj, String filePath, boolean standarXml){
        String strXml = toXml(obj);
        File file = new File(filePath);
        if(!file.exists()){
            try {
                boolean newFile = file.createNewFile();
                log.info("创建新文件：{} {} {} {}", obj, filePath, standarXml, newFile);
            } catch (IOException e) {
                log.error("", e);
                return false ;
            }
        }
        if(standarXml){
            strXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + strXml;
        }
        return writeFile(strXml, file) ;
    }

}
